# book_server.py
# gRPC服务器实现

import time
import grpc
from concurrent import futures
import book_service_pb2
import book_service_pb2_grpc

# 创建一个示例图书数据库
BOOKS_DB = {
    1: book_service_pb2.Book(id=1, title="深入理解Python", author="张三", year=2020),
    2: book_service_pb2.Book(id=2, title="gRPC入门与实践", author="李四", year=2021),
    3: book_service_pb2.Book(id=3, title="分布式系统设计", author="王五", year=2019),
}


class BookServiceServicer(book_service_pb2_grpc.BookServiceServicer):
    """
    实现gRPC服务定义的服务器端
    """

    def GetBook(self, request, context):
        """
        实现简单RPC：根据ID获取图书信息

        参数:
            request: BookRequest 请求对象
            context: RPC上下文

        返回:
            Book 消息对象
        """
        # 检查请求的图书是否存在
        if request.id in BOOKS_DB:
            # 返回找到的图书
            return BOOKS_DB[request.id]
        else:
            # 如果找不到图书，设置错误状态码和消息
            context.set_code(grpc.StatusCode.NOT_FOUND)
            context.set_details(f"图书ID {request.id} 不存在")
            return book_service_pb2.Book()

    def ListBooks(self, request, context):
        """
        实现服务器流式RPC：获取所有图书列表

        参数:
            request: Empty 空请求对象
            context: RPC上下文

        返回:
            生成器，产生多个Book对象
        """
        # 遍历数据库中的所有图书
        for book in BOOKS_DB.values():
            # 模拟一些处理时间
            time.sleep(0.5)
            # 逐个返回图书信息
            yield book

    def AddBooks(self, request_iterator, context):
        """
        实现客户端流式RPC：添加多本书

        参数:
            request_iterator: 客户端发送的Book流
            context: RPC上下文

        返回:
            AddBooksResponse 响应对象
        """
        added_count = 0

        # 处理客户端发送的每一本书
        for book in request_iterator:
            # 检查图书ID是否已存在
            if book.id in BOOKS_DB:
                continue

            # 将新书添加到数据库
            BOOKS_DB[book.id] = book
            added_count += 1
            print(f"服务器端输出：已添加图书: {book.title}")

        # 返回添加结果
        return book_service_pb2.AddBooksResponse(
            success=True,
            books_added=added_count,
            message=f"成功添加了 {added_count} 本图书",
        )

    def WatchBooks(self, request_iterator, context):
        """
        实现双向流式RPC：实时获取图书更新

        参数:
            request_iterator: 客户端发送的BookRequest流
            context: RPC上下文

        返回:
            生成器，产生对应的Book对象
        """
        # 处理客户端发送的每个请求
        for request in request_iterator:
            # 检查请求的图书是否存在
            if request.id in BOOKS_DB:
                # 模拟一些处理时间
                time.sleep(0.5)
                # 返回找到的图书
                yield BOOKS_DB[request.id]
            else:
                # 如果找不到相应的图书，可以通过context设置错误
                # 但在流式RPC中，我们可以选择忽略错误请求，继续处理其他请求
                # 模拟一些处理时间
                time.sleep(0.5)
                print(f"服务器端输出：警告: 图书ID {request.id} 不存在")


def serve():
    """
    启动gRPC服务器
    """
    # 创建服务器对象，最大允许10个并发连接
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

    # 服务器监听的地址和端口
    server_address = "[::]:50051"
    server.add_insecure_port(server_address)

    # 将我们的服务实现添加到服务器
    book_service_pb2_grpc.add_BookServiceServicer_to_server(
        BookServiceServicer(), server
    )

    # 启动服务器
    server.start()
    print(f"服务器已启动，监听地址: {server_address}")

    try:
        # 保持服务器运行直到被中断
        server.wait_for_termination()
    except KeyboardInterrupt:
        print("服务器已停止")


if __name__ == "__main__":
    serve()
